package com.util;

import java.util.HashMap;
import java.util.Stack;

public class Counter {
	private static final char[]	chars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',  'A', 'B', 'C',
			'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };

	private static final HashMap<Character, Integer> charNumberMap	= new HashMap<Character, Integer>();
	private static final Integer scale = chars.length;

	static {
		for (int i = 0; i < chars.length; i++) {
			charNumberMap.put(chars[i], i);
		}
	}

	public static synchronized String getNext(String counter) {
		counter = counter.toUpperCase();
		long currentNumberIn10 = strToNumber(counter);
		currentNumberIn10 = currentNumberIn10 + 1;
		return numberToStr(currentNumberIn10);
	}
	
	private static synchronized Integer getPositionNumber(char chars) {
		Integer poi = charNumberMap.get(chars);
		if (poi != null) {
			return poi;
		} else {
			throw new RuntimeException("invalid character " + chars);
		}
	}

	public static synchronized long strToNumber(String counter) {
		counter = counter.toUpperCase();
		Stack<Integer> numberStack = new Stack<Integer>();
		// example: 10dk will be cut to 1 0 d k, and 1 will put to the bottom of
		// the stack
		for (int i = 0; i < counter.length(); i++) {
			char currentChar = counter.charAt(i);
			int poi = getPositionNumber(currentChar);
			numberStack.push(poi);// biggest number at last
		}
		long result = 0l;
		if (numberStack != null) {
			long plus = 1;
			while (!numberStack.isEmpty()) {
				Integer number = numberStack.pop();
				result = result + (number * plus);
				plus = plus * scale;
				if(result < 0){
					throw new RuntimeException("number out of range");
				}
			}
		} 
		return result;
	}

	public static synchronized String numberToStr(long number) {
		if(number < 0){
			throw new RuntimeException("number out of range");
		}
		long result = number / scale;
		int modResult = (int) (number % scale);
		char modChar = chars[modResult];
		Stack<Character> resultStack = new Stack<Character>();
		resultStack.push(modChar);
		while (result > 0) {
			modResult = (int) (result % scale);
			modChar = chars[modResult];
			result = result / scale;
			resultStack.push(modChar);
		}
		StringBuffer resultStringBuffer = new StringBuffer();
		if (resultStack != null) {
			while (!resultStack.isEmpty()) {
				resultStringBuffer.append(resultStack.pop());
			}
		} 
		return resultStringBuffer.toString();
	}
	
	public static void main(String[] args) {
		System.out.println(Counter.strToNumber("1qpunU"));
		System.out.println(Counter.numberToStr(13969525655l));
		
	}
	

}
